/*
    arm data process instructions
    Copyright (C) 2011  Jiabo <jiabo2011@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#define ARITH_and 0x0
#define ARITH_eor 0x1
#define ARITH_sub 0x2
#define ARITH_rsb 0x3
#define ARITH_add 0x4
#define ARITH_adc 0x5
#define ARITH_sbc 0x6
#define ARITH_rsc 0x7
#define ARITH_tst 0x8
#define ARITH_cmp 0xa
#define ARITH_cmn 0xb
#define ARITH_orr 0xc
#define ARITH_mov 0xd
#define ARITH_bic 0xe
#define ARITH_mvn 0xf

#define DATA_OPC1(DATA_OPC)\
static inline void arm_ ## DATA_OPC ## _reg_cond(uint8_t cond,\
	uint8_t rd, uint8_t rn, uint8_t rm)\
{\
	*gen_code_ptr++ = (cond << 28) |\
		(ARITH_ ## DATA_OPC << 21) | (rd << 12) | (rn << 16) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg(uint8_t rd, uint8_t rn, uint8_t rm)\
{\
	arm_ ## DATA_OPC ## _reg_cond(COND_AL, rd, rn, rm);\
}\
static inline void arm_ ## DATA_OPC ## s_reg(uint8_t rd, uint8_t rn, uint8_t rm)\
{\
	*gen_code_ptr++ = (COND_AL << 28) |\
		(ARITH_ ## DATA_OPC << 21) | (1 << 20) | (rd << 12) | (rn << 16) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_lsl_imm(uint8_t rd,\
	uint8_t rn, uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000000 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsl_reg(uint8_t rd,\
	uint8_t rn, uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000010 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsr_imm(uint8_t rd,\
	uint8_t rn, uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000020 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsr_reg(uint8_t rd,\
	uint8_t rn, uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000030 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_asr_imm(uint8_t rd,\
	uint8_t rn, uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000040 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_asr_reg(uint8_t rd,\
	uint8_t rn, uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000050 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | (rs << 8) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_imm_cond(uint8_t cond,\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	*gen_code_ptr++ = 0x02000000 | (cond << 28) |  (ARITH_ ## DATA_OPC << 21) |\
		(reg << 12) | (reg << 16) | ((rorate_imm & 0xf) << 8) | immed_8;\
}\
\
static inline void arm_ ## DATA_OPC ## s_reg_imm_cond(uint8_t cond,\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	*gen_code_ptr++ = 0x02000000 | (cond << 28) |  (ARITH_ ## DATA_OPC << 21) |\
		(1 << 20) | (reg << 12) | (reg << 16) | ((rorate_imm & 0xf) << 8) | immed_8;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_imm(\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	arm_ ## DATA_OPC ## _reg_imm_cond(COND_AL, reg, immed_8, rorate_imm);\
}\
\
static inline void arm_ ## DATA_OPC ## s_reg_imm(\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	arm_ ## DATA_OPC ## s_reg_imm_cond(COND_AL, reg, immed_8, rorate_imm);\
}\
\
static inline void arm_ ## DATA_OPC ## _rd_rn_imm(\
	uint8_t rd, uint8_t rn, uint8_t immed_8, uint8_t rorate_imm)\
{\
	*gen_code_ptr++ = 0xe2000000 |  (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | ((rorate_imm & 0xf) << 8) | immed_8;\
}\
\
static inline void arm_ ## DATA_OPC ## _rd_rn_imm_cond(uint8_t cond,\
	uint8_t rd, uint8_t rn, uint8_t immed_8, uint8_t rorate_imm)\
{\
	*gen_code_ptr++ = 0x02000000 | (cond << 28) |  (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rn << 16) | ((rorate_imm & 0xf) << 8) | immed_8;\
}

#define DATA_OPC2(DATA_OPC)\
static inline void arm_ ## DATA_OPC ## _reg_cond(uint8_t cond,\
	uint8_t rd, uint8_t rm)\
{\
	*gen_code_ptr++ = (cond << 28) |\
		(ARITH_ ## DATA_OPC << 21) | (rd << 12) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg(uint8_t rd, uint8_t rm)\
{\
	arm_ ## DATA_OPC ## _reg_cond(COND_AL, rd, rm);\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_lsl_imm(uint8_t rd,\
	uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000000 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsl_reg(uint8_t rd,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000010 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsr_imm(uint8_t rd,\
	uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000020 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsr_reg(uint8_t rd,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000030 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## s_reg_lsr_reg(uint8_t rd,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000030 | (ARITH_ ## DATA_OPC << 21) |\
		(1 << 20) |(rd << 12) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_asr_imm(uint8_t rd,\
	uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000040 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_asr_reg(uint8_t rd,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000050 | (ARITH_ ## DATA_OPC << 21) |\
		(rd << 12) | (rs << 8) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_imm_cond(uint8_t cond,\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	*gen_code_ptr++ = 0x02000000 | (cond << 28) |  (ARITH_ ## DATA_OPC << 21) |\
		(reg << 12) | ((rorate_imm & 0xf) << 8) | immed_8;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_imm(\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	arm_ ## DATA_OPC ## _reg_imm_cond(COND_AL, reg, immed_8, rorate_imm);\
}

#define DATA_OPC3(DATA_OPC)\
static inline void arm_ ## DATA_OPC ## _reg_cond(uint8_t cond,\
	uint8_t rn, uint8_t rm)\
{\
	*gen_code_ptr++ = (cond << 28) |\
		(ARITH_ ## DATA_OPC << 21) | (1 << 20) | (rn << 16) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg(uint8_t rn, uint8_t rm)\
{\
	arm_ ## DATA_OPC ## _reg_cond(COND_AL, rn, rm);\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_lsl_imm(uint8_t rn,\
	uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000000 | (ARITH_ ## DATA_OPC << 21) | (1 << 20) |\
		(rn << 16) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsl_reg(uint8_t rn,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000010 | (ARITH_ ## DATA_OPC << 21) | (1 << 20) |\
		(rn << 16) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsr_imm(uint8_t rn,\
	uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000020 | (ARITH_ ## DATA_OPC << 21) | (1 << 20) |\
		(rn << 16) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_lsr_reg(uint8_t rn,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000030 | (ARITH_ ## DATA_OPC << 21) | (1 << 20) |\
		(rn << 16) | (rs << 8) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_asr_imm(uint8_t rn,\
	uint8_t rm, uint8_t shift)\
{\
	*gen_code_ptr++ = 0xe0000040 | (ARITH_ ## DATA_OPC << 21) | (1 << 20) |\
		(rn << 16) | ((shift & 0x1f) << 7) | rm;\
}\
static inline void arm_ ## DATA_OPC ## _reg_asr_reg(uint8_t rn,\
	uint8_t rm, uint8_t rs)\
{\
	*gen_code_ptr++ = 0xe0000050 | (ARITH_ ## DATA_OPC << 21) | (1 << 20) |\
		(rn << 16) | (rs << 8) | rm;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_imm_cond(uint8_t cond,\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	*gen_code_ptr++ = 0x02000000 | (cond << 28) |  (ARITH_ ## DATA_OPC << 21) |\
		(1 << 20) |(reg << 16) | ((rorate_imm & 0xf) << 8) | immed_8;\
}\
\
static inline void arm_ ## DATA_OPC ## _reg_imm(\
	uint8_t reg, uint8_t immed_8, uint8_t rorate_imm)\
{\
	arm_ ## DATA_OPC ## _reg_imm_cond(COND_AL, reg, immed_8, rorate_imm);\
}

DATA_OPC1(add)
DATA_OPC1(and)
DATA_OPC1(bic)
DATA_OPC1(eor)
DATA_OPC1(orr)
DATA_OPC1(sub)
DATA_OPC1(rsb)

DATA_OPC2(mov)
DATA_OPC2(mvn)

DATA_OPC3(cmp)
DATA_OPC3(tst)
